{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# {func}`~tvm.relay.qnn.transform.FTVMQnnLegalize`\n",
    "\n",
    "源码：`tvm/python/tvm/relay/qnn/transform.py` & `tvm/src/relay/qnn/pass/legalize.cc`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import testing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0;31mSignature:\u001b[0m \u001b[0mregister_qnn_legalize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mop_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlegal_op\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mDocstring:\u001b[0m\n",
      "Register legal transformation function for a QNN op.\n",
      "\n",
      "This helps QNN match hardware intrinsics better and is run before\n",
      "canonicalization.\n",
      "\n",
      "Parameters\n",
      "----------\n",
      "op_name : str\n",
      "    The name of the operator\n",
      "\n",
      "legal_op: function (attrs: Attrs, inputs: List[Expr]) -> new_expr: Expr\n",
      "    The function for transforming an expr to another expr.\n",
      "\n",
      "level : int\n",
      "    The priority level\n",
      "\u001b[0;31mFile:\u001b[0m      /media/pc/data/lxw/ai/tvm/python/tvm/relay/qnn/op/op.py\n",
      "\u001b[0;31mType:\u001b[0m      function"
     ]
    }
   ],
   "source": [
    "from tvm.relay.qnn.op import register_qnn_legalize\n",
    "\n",
    "register_qnn_legalize?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0;31mSignature:\u001b[0m \u001b[0mLegalize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mDocstring:\u001b[0m\n",
      "Legalizes QNN ops. As opposed to Relay Legalize, this one legalizes only QNN ops. One can\n",
      "register a transformation/legalization function for an op by using the FTVMQnnLegalize attr_name\n",
      "for FTVMLegalize op attribute. The isolation of QNN and Relay Legalize gives us separation of\n",
      "concerns, leading to a better software practice. The legalization can be configured to happen\n",
      "per target. An example of this type of legalization is shown below.\n",
      "\n",
      "Examples\n",
      "________\n",
      "\n",
      "Suppose the original graph is as follows\n",
      "\n",
      "        data(u8)  weight(u8)\n",
      "            |       |\n",
      "            |       |\n",
      "           qnn.conv2d (int32)\n",
      "               |\n",
      "               |\n",
      "            nn.relu (int32)\n",
      "\n",
      "Now, we know that Intel Cascade Lake has VNNI instructions to speedup convolution. However, it\n",
      "only works on u8 x i8 inputs. So, here, we can use QNN Legalize to transform the above graph as\n",
      "follows\n",
      "\n",
      "        data(u8)  weight(u8)\n",
      "           |          |\n",
      "           |          |\n",
      "           |     requantize(i8)\n",
      "           |        |\n",
      "           |        |\n",
      "           qnn.conv2d (int32)\n",
      "               |\n",
      "               |\n",
      "             nn.relu (int32)\n",
      "\n",
      "In this legalization, since we have isolated legalization for QNN ops, it will only trigger the\n",
      "transformation for qnn.conv2d (and not nn.relu). This pass can be followed by CanonicalizeOps to\n",
      "further lower the qnn.requantize and qnn.conv2d into an expr containing only Relay ops.\n",
      "\n",
      "Returns\n",
      "-------\n",
      "ret : tvm.transform.Pass\n",
      "    The registered pass that legalizes QNN ops.\n",
      "\u001b[0;31mFile:\u001b[0m      /media/pc/data/lxw/ai/tvm/python/tvm/relay/qnn/transform.py\n",
      "\u001b[0;31mType:\u001b[0m      function"
     ]
    }
   ],
   "source": [
    "from tvm.relay.qnn.transform import Legalize\n",
    "\n",
    "Legalize?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这段代码定义了一个名为 `Legalize` 的函数，它的作用是将 QNN 算子合法化。与 Relay Legalize 不同，这个函数只对 QNN 算子进行合法化。可以通过使用 `FTVMQnnLegalize` 属性名称为 `FTVMLegalize` 算子属性注册一个算子的 transformation/legalization 函数。QNN 和 Relay Legalize 的隔离使我们能够更好地分离关注点，从而得到更好的软件实践。合法化可以针对每个目标进行配置。\n",
    "\n",
    "假设原始图如下：\n",
    "\n",
    "```\n",
    "        data(u8)  weight(u8)\n",
    "            |       |\n",
    "            |       |\n",
    "           qnn.conv2d (int32)\n",
    "               |\n",
    "               |\n",
    "            nn.relu (int32)\n",
    "```\n",
    "\n",
    "现在，我们知道 Intel Cascade Lake 有 VNNI 指令来加速卷积。然而，它只适用于 u8 x i8 输入。因此，在这里，我们可以使用 QNN Legalize 将上述图转换为以下形式：\n",
    "\n",
    "```\n",
    "        data(u8)  weight(u8)\n",
    "           |          |\n",
    "           |          |\n",
    "           |     requantize(i8)\n",
    "           |        |\n",
    "           |        |\n",
    "           qnn.conv2d (int32)\n",
    "               |\n",
    "               |\n",
    "             nn.relu (int32)\n",
    "```\n",
    "\n",
    "在这个合法化中，由于我们已经为 QNN 算子进行了隔离合法化，它只会触发 `qnn.conv2d` （而不是 `nn.relu`）的转换。此传递可以跟随 `CanonicalizeOps` 进一步将 `qnn.requantize` 和 `qnn.conv2d` 降低为仅包含 Relay 算子的表达式。\n",
    "\n",
    "函数返回 `tvm.transform.Pass` 对象，该对象将 QNN 算子合法化。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py312x",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.1.-1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
